home *** CD-ROM | disk | FTP | other *** search
/ Gekikoh Dennoh Club 5 / Gekikoh Dennoh Club Vol. 5 (Japan).7z / Gekikoh Dennoh Club Vol. 5 (Japan) (Track 01).bin / internet / xip / iijppp.lzh / src / modem.c < prev    next >
C/C++ Source or Header  |  1994-10-21  |  13KB  |  590 lines

  1. /*
  2.  *        PPP Modem handling module
  3.  *
  4.  *        Written by Toshiharu OHNO (tony-o@iij.ad.jp)
  5.  *
  6.  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that the above copyright notice and this paragraph are
  10.  * duplicated in all such forms and that any documentation,
  11.  * advertising materials, and other materials related to such
  12.  * distribution and use acknowledge that the software was developed
  13.  * by the Internet Initiative Japan, Inc.  The name of the
  14.  * IIJ may not be used to endorse or promote products derived
  15.  * from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  *
  20.  *  TODO:
  21.  */
  22. #include "fsm.h"
  23. #include <fcntl.h>
  24. #include <termios.h>
  25. #include <sys/ioctl.h>
  26. #include "hdlc.h"
  27. #include "lcp.h"
  28. #include "modem.h"
  29. #include "vars.h"
  30.  
  31. extern int DoChat();
  32.  
  33. static int mbits;            /* Current DCD status */
  34. static int connect_time;        /* connection time */
  35. static int connect_count;
  36. static struct pppTimer ModemTimer;
  37. static char *uucplock;
  38.  
  39. extern int uu_lock(), uu_unlock();
  40. extern void PacketMode();
  41.  
  42. #define    Online    (mbits & TIOCM_CD)
  43.  
  44. static struct mbuf *modemout;
  45. static struct mqueue OutputQueues[PRI_URGENT+1];
  46. static int dev_is_modem;
  47.  
  48. void
  49. Enqueue(queue, bp)
  50. struct mqueue *queue;
  51. struct mbuf *bp;
  52. {
  53.   if (queue->last) {
  54.     queue->last->pnext = bp;
  55.     queue->last = bp;
  56.   } else
  57.     queue->last = queue->top = bp;
  58.   queue->qlen++;
  59. #ifdef QDEBUG
  60.   logprintf("Enqueue: len = %d\n", queue->qlen);
  61. #endif
  62. }
  63.  
  64. struct mbuf *
  65. Dequeue(queue)
  66. struct mqueue *queue;
  67. {
  68.   struct mbuf *bp;
  69.  
  70. #ifdef QDEBUG
  71.   logprintf("Dequeue: len = %d\n", queue->qlen);
  72. #endif
  73.   if (bp = queue->top) {
  74.     queue->top = queue->top->pnext;
  75.     queue->qlen--;
  76.     if (queue->top == NULL) {
  77.       queue->last = queue->top;
  78. #ifdef QDEBUG
  79.       if (queue->qlen)
  80.     logprintf("!!! not zero (%d)!!!\n", queue->qlen);
  81. #endif
  82.     }
  83.   }
  84.   return(bp);
  85. }
  86.  
  87. static time_t uptime;
  88.  
  89. void
  90. DownConnection()
  91. {
  92.   LogPrintf(LOG_PHASE, "Disconnected!\n");
  93.   LogPrintf(LOG_PHASE, "Connect time: %d secs\n", time(NULL) - uptime);
  94.   LcpDown();
  95.   connect_time = 0;
  96. }
  97.  
  98. /*
  99.  *  ModemTimeout() watches DCD signal and notifies if it's status is changed.
  100.  *
  101.  */
  102. void
  103. ModemTimeout()
  104. {
  105.   int ombits = mbits;
  106.   int change;
  107.  
  108.   StopTimer(&ModemTimer);
  109.   if (Online)
  110.     connect_time++;
  111.   StartTimer(&ModemTimer);
  112.  
  113.   if (dev_is_modem) {
  114.     ioctl(modem, TIOCMGET, &mbits);
  115.     change = ombits ^ mbits;
  116.     if (change & TIOCM_CD) {
  117.       if (Online) {
  118.         time(&uptime);
  119.         LogPrintf(LOG_PHASE, "*Connected!\n");
  120.         connect_count++;
  121.         /*
  122.          * In dedicated mode, start packet mode immediate
  123.          * after we detected carrier.
  124.          */
  125.         if (mode & MODE_DEDICATED)
  126.       PacketMode();
  127.       } else {
  128.     DownConnection();
  129.       }
  130.     }
  131.   } else {
  132.     if (!Online) {
  133. online:
  134.       time(&uptime);
  135.       LogPrintf(LOG_PHASE, "Connected!\n");
  136.       mbits = TIOCM_CD;
  137.       connect_count++;
  138.       connect_time = 0;
  139.     }
  140.   }
  141. }
  142.  
  143. void
  144. StartModemTimer()
  145. {
  146.   connect_time = 0;
  147.   StopTimer(&ModemTimer);
  148.   ModemTimer.state = TIMER_STOPPED;
  149.   ModemTimer.load = SECTICKS;
  150.   ModemTimer.func = ModemTimeout;
  151.   StartTimer(&ModemTimer);
  152. }
  153.  
  154. struct parity {
  155.   char *name;
  156.   char *name1;
  157.   int  set;
  158. } validparity[] = {
  159.   { "even", "P_EVEN", CS7 | PARENB }, { "odd", "P_ODD", CS7 | PARENB | PARODD },
  160.   { "none", "P_ZERO", CS8 },          { NULL,  0 },
  161. };
  162.  
  163. int
  164. GetParityValue(str)
  165. char *str;
  166. {
  167.   struct parity *pp;
  168.  
  169.   for (pp = validparity; pp->name; pp++) {
  170.     if (strcasecmp(pp->name, str) == 0 ||
  171.     strcasecmp(pp->name1, str) == 0) {
  172.       VarParity = pp->set;
  173.       return(pp->set);
  174.     }
  175.   }
  176.   return(-1);
  177. }
  178.  
  179. int
  180. ChangeParity(str)
  181. char *str;
  182. {
  183.   struct termios rstio;
  184.   int val;
  185.  
  186.   val = GetParityValue(str);
  187.   if (val > 0) {
  188.     VarParity = val;
  189.     ioctl(modem, TIOCGETA, &rstio);
  190.     rstio.c_cflag &= ~(CSIZE|PARODD|PARENB);
  191.     rstio.c_cflag |= val;
  192.     ioctl(modem, TIOCSETA, &rstio);
  193.   }
  194.   return(val);
  195. }
  196.  
  197. #include <sys/socket.h>
  198. #include <arpa/inet.h>
  199. #include <netdb.h>
  200.  
  201. int
  202. OpenConnection(host, port)
  203. char *host, *port;
  204. {
  205.   struct sockaddr_in dest;
  206.   int sock;
  207.   struct hostent *hp;
  208.   struct servent *sp;
  209.  
  210.   dest.sin_family = AF_INET;
  211.   dest.sin_addr.s_addr = inet_addr(host);
  212.   if (dest.sin_addr.s_addr == INADDR_NONE) {
  213.     hp = gethostbyname(host);
  214.     if (hp) {
  215.       bcopy(hp->h_addr_list[0], &dest.sin_addr.s_addr, 4);
  216.     } else {
  217.       printf("unknown host: %s\n", host);
  218.       return(-1);
  219.     }
  220.   }
  221.   dest.sin_port = htons(atoi(port));
  222.   if (dest.sin_port == 0) {
  223.     sp = getservbyname(port, "tcp");
  224.     if (sp) {
  225.       dest.sin_port = sp->s_port;
  226.     } else {
  227.       printf("unknown service: %s\n", port);
  228.       return(-1);
  229.     }
  230.   }
  231.   LogPrintf(LOG_PHASE, "Connected to %s:%s\n", host, port);
  232.  
  233.   sock = socket(PF_INET, SOCK_STREAM, 0);
  234.   if (sock < 0) {
  235.     return(sock);
  236.   }
  237.   if (connect(sock, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
  238.     printf("connection failed.\n");
  239.     return(-1);
  240.   }
  241.   return(sock);
  242. }
  243.  
  244. int
  245. OpenModem(mode)
  246. int mode;
  247. {
  248.   struct termios rstio;
  249.   int oldflag;
  250.   char *host, *cp, *port;
  251.  
  252.   mbits = 0;
  253.   if (mode & MODE_DIRECT) {
  254.     if (isatty(0))
  255.       modem = open("/dev/tty", O_RDWR|O_NONBLOCK);
  256.   } else if (modem == 0) {
  257.     if (strncmp(VarDevice, "/dev", 4) == 0) {
  258.       uucplock = rindex(VarDevice, '/')+1;
  259.       if (uu_lock(uucplock) < 0) {
  260.         fprintf(stderr, "modem is in use.\n");
  261.         return(-1);
  262.       }
  263.       modem = open(VarDevice, O_RDWR|O_NONBLOCK);
  264.       if (modem < 0) {
  265.         perror("open modem");
  266.         return(modem);
  267.       }
  268.     } else {
  269.       /* XXX: PPP over TCP */
  270.       cp = index(VarDevice, ':');
  271.       if (cp) {
  272.     *cp = 0;
  273.     host = VarDevice;
  274.     port =  cp + 1;
  275.     if (*host && *port) {
  276.       modem = OpenConnection(host, port);
  277.           *cp = ':';    /* Don't destroy VarDevice */
  278.       if (modem < 0) return(-1);
  279.     } else {
  280.           *cp = ':';    /* Don't destroy VarDevice */
  281.       return(-1);
  282.     }
  283.       } else
  284.     return(-1);
  285.     }
  286.   }
  287.  
  288.   while (modem < 3)
  289.     modem = dup(modem);
  290.  
  291.   /*
  292.    * If we are working on tty device, change it's mode into
  293.    * the one desired for further operation. In this implementation,
  294.    * we assume that modem is configuted to use CTS/RTS flow control.
  295.    */
  296.   if (dev_is_modem = isatty(modem)) {
  297.     ioctl(modem, TIOCGETA, &rstio);
  298. #ifdef DEBUG
  299.     logprintf("## modem = %d\n", modem);
  300.     logprintf("modem (get): iflag = %x, oflag = %x, cflag = %x\n",
  301.     rstio.c_iflag, rstio.c_oflag, rstio.c_cflag);
  302. #endif
  303. #define USE_CTSRTS
  304. #ifdef USE_CTSRTS
  305.     rstio.c_cflag = (CS8 | CREAD | CLOCAL | CCTS_OFLOW|CRTS_IFLOW);
  306. #else
  307.     rstio.c_cflag = (CS8 | CREAD | CLOCAL);
  308. #endif
  309.     if ((mode & MODE_DIRECT) == 0) {
  310.       /*
  311.        * If we are working as direct mode, don't change tty speed.
  312.        */
  313.       rstio.c_cflag &= ~(CSIZE|PARENB|PARODD);
  314.       rstio.c_cflag |= VarParity;
  315.       rstio.c_ispeed = rstio.c_ospeed = VarSpeed;
  316.     }
  317.     rstio.c_iflag |= (IGNBRK | ISTRIP | IGNPAR | IXON | IXOFF);
  318.     rstio.c_iflag &= ~(BRKINT|ICRNL|IXANY|IMAXBEL);
  319.     rstio.c_lflag = 0;
  320.  
  321.     rstio.c_oflag &= ~OPOST;
  322. #ifdef notdef
  323.     rstio.c_cc[VMIN] = 10;
  324.     rstio.c_cc[VTIME] = 1;
  325. #else
  326.     rstio.c_cc[VMIN] = 1;
  327.     rstio.c_cc[VTIME] = 0;
  328. #endif
  329.     ioctl(modem, TIOCSETA, &rstio);
  330. #ifdef DEBUG
  331.     logprintf("modem (put): iflag = %x, oflag = %x, cflag = %x\n",
  332.     rstio.c_iflag, rstio.c_oflag, rstio.c_cflag);
  333. #endif
  334.  
  335. #ifdef DEBUG
  336.     ioctl(modem, TIOCMGET, &mbits);
  337.     fprintf(stderr, "modem control = %o\n", mbits);
  338. #endif
  339.  
  340.     oldflag = fcntl(modem, F_GETFL, 0);
  341.     fcntl(modem, F_SETFL, oldflag & ~O_NDELAY);
  342.   }
  343.   StartModemTimer();
  344.  
  345.   return(modem);
  346. }
  347.  
  348. int
  349. ModemSpeed()
  350. {
  351.   struct termios rstio;
  352.  
  353.   ioctl(modem, TIOCGETA, &rstio);
  354.   return(rstio.c_ispeed);
  355. }
  356.  
  357. static struct termios modemios;
  358.  
  359. /*
  360.  * Put modem tty line into raw mode which is necessary in packet mode operation
  361.  */
  362. int
  363. RawModem(modem)
  364. int modem;
  365. {
  366.   struct termios rstio;
  367.   int oldflag;
  368.  
  369.   if (!isatty(modem))
  370.     return(0);
  371.   if (!(mode & MODE_DIRECT) && modem && !Online) {
  372. #ifdef DEBUG
  373.     logprintf("mode = %d, modem = %d, mbits = %x\n", mode, modem, mbits);
  374. #endif
  375. #ifdef notdef
  376.     return(-1);
  377. #endif
  378.   }
  379.   ioctl(modem, TIOCGETA, &rstio);
  380.   modemios = rstio;
  381.   rstio.c_cflag &= ~(CSIZE|PARENB|PARODD);
  382.   rstio.c_cflag |= CS8;
  383.   rstio.c_iflag &= ~(ISTRIP|IXON|IXOFF|BRKINT|ICRNL|INLCR);
  384.   ioctl(modem, TIOCSETA, &rstio);
  385.   oldflag = fcntl(modem, F_GETFL, 0);
  386.   fcntl(modem, F_SETFL, oldflag | O_NDELAY);
  387. #ifdef DEBUG
  388.   oldflag = fcntl(modem, F_GETFL, 0);
  389.   logprintf("modem (put2): iflag = %x, oflag = %x, cflag = %x\n",
  390.    rstio.c_iflag, rstio.c_oflag, rstio.c_cflag);
  391.   logprintf("flag = %x\n", oldflag);
  392. #endif
  393.   return(0);
  394. }
  395.  
  396. void
  397. UnrawModem(modem)
  398. int modem;
  399. {
  400.   int oldflag;
  401.  
  402.   if (isatty(modem)) {
  403.     ioctl(modem, TIOCSETA, &modemios);
  404.     oldflag = fcntl(modem, F_GETFL, 0);
  405.     fcntl(modem, F_SETFL, oldflag & ~O_NDELAY);
  406.   }
  407. }
  408.  
  409. void
  410. HangupModem(flag)
  411. int flag;
  412. {
  413.   int n = 0;
  414.  
  415.   if (!isatty(modem)) {
  416.     mbits &= ~TIOCM_DTR;
  417.     close(modem);
  418.     modem = 0;            /* Mark as modem has closed */
  419.     return;
  420.   }
  421.  
  422.   if (Online) {
  423.     mbits &= ~TIOCM_DTR;
  424.     ioctl(modem, TIOCMSET, &mbits);
  425.     sleep(1);
  426. #ifdef notdef
  427.     mbits &= ~TIOCM_CD;
  428. #endif
  429.   }
  430.   /*
  431.    * If we are working as dedicated mode, never close it
  432.    * until we are directed to quit program.
  433.    */
  434.   if (modem && (flag || !(mode & MODE_DEDICATED))) {
  435.     ModemTimeout();            /* XXX */
  436.     StopTimer(&ModemTimer);        /* XXX */
  437.     ioctl(modem, TIOCFLUSH, &n);
  438.     UnrawModem(modem);
  439.     close(modem);
  440.     (void) uu_unlock(uucplock);
  441.     modem = 0;            /* Mark as modem has closed */
  442.   } else {
  443.     mbits |= TIOCM_DTR;
  444.     ioctl(modem, TIOCMSET, &mbits);
  445.   }
  446. }
  447.  
  448. CloseModem()
  449. {
  450.   close(modem);
  451.   modem = 0;
  452.   (void) uu_unlock(uucplock);
  453. }
  454.  
  455. /*
  456.  * Write to modem. Actualy, requested packets are queued, and goes out
  457.  * to the line when ModemStartOutput() is called.
  458.  */
  459. void
  460. WriteModem(pri, ptr, count)
  461. int pri;
  462. char *ptr;
  463. int count;
  464. {
  465.   struct mbuf *bp;
  466.  
  467.   bp = mballoc(count, MB_MODEM);
  468.   bcopy(ptr, MBUF_CTOP(bp), count);
  469.   Enqueue(&OutputQueues[pri], bp);
  470. }
  471.  
  472. int
  473. ModemQlen()
  474. {
  475.   struct mbuf *bp;
  476.   int len = 0;
  477.   int i;
  478.  
  479.   for (i = PRI_NORMAL; i <= PRI_URGENT; i++) {
  480.     for (bp = OutputQueues[i].top; bp; bp = bp->pnext)
  481.       len++;
  482.   }
  483.  
  484.   return(len);
  485. }
  486.  
  487. void
  488. ModemStartOutput(fd)
  489. int fd;
  490. {
  491.   struct mqueue *queue;
  492.   int nb, nw, i;
  493.  
  494.   if (modemout == NULL) {
  495.     i = 0;
  496.     for (queue = &OutputQueues[PRI_URGENT]; queue >= OutputQueues; queue--) {
  497.       if (queue->top) {
  498.     modemout = Dequeue(queue);
  499. #ifdef QDEBUG
  500.     if (i < 2) {
  501.       struct mqueue *q;
  502.  
  503.       q = &OutputQueues[0];
  504.       logprintf("output from queue %d, normal has %d\n", i, q->qlen);
  505.     }
  506.     logprintf("Dequeue(%d): ", i);
  507. #endif
  508.     break;
  509.       }
  510.       i++;
  511.     }
  512.   }
  513.   if (modemout) {
  514.     nb = modemout->cnt;
  515.     if (nb > 300) nb = 300;
  516.     if (fd == 0) fd = 1;
  517.     nw = write(fd, MBUF_CTOP(modemout), nb);
  518. #ifdef QDEBUG
  519.     logprintf("wrote: %d(%d)\n", nw, nb);
  520.     LogDumpBuff(LOG_HDLC, "modem write", MBUF_CTOP(modemout), nb);
  521. #endif
  522.     if (nw > 0) {
  523.       modemout->cnt -= nw;
  524.       modemout->offset += nw;
  525.       if (modemout->cnt == 0) {
  526.     modemout = mbfree(modemout);
  527. #ifdef QDEBUG
  528.     logprintf(" mbfree\n");
  529. #endif
  530.       }
  531.     } else if (nw < 0)
  532.       perror("modem write");
  533.   }
  534. }
  535.  
  536. int
  537. DialModem()
  538. {
  539.   char ScriptBuffer[200];
  540.  
  541.   strcpy(ScriptBuffer, VarDialScript);
  542.   if (DoChat(ScriptBuffer) > 0) {
  543.     fprintf(stderr, "dial OK!\n");
  544.     strcpy(ScriptBuffer, VarLoginScript);
  545.     if (DoChat(ScriptBuffer) > 0) {
  546.       fprintf(stderr, "login OK!\n");
  547.       return(1);
  548.     } else {
  549.       fprintf(stderr, "login failed.\n");
  550.     }
  551.     ModemTimeout();    /* Dummy call to check modem status */
  552.   }
  553.   else
  554.     fprintf(stderr, "dial failed.\n");
  555.   return(0);
  556. }
  557.  
  558. int
  559. ShowModemStatus()
  560. {
  561.   int nb;
  562.  
  563.   printf("device: %s  speed: %d\n", VarDevice, VarSpeed);
  564.   switch (VarParity & CSIZE) {
  565.   case CS7:
  566.     printf("cs7, ");
  567.     break;
  568.   case CS8:
  569.     printf("cs8, ");
  570.     break;
  571.   }
  572.   if (VarParity & PARENB) {
  573.     if (VarParity & PARODD)
  574.       printf("odd parity\n");
  575.     else
  576.       printf("even parity\n");
  577.   } else
  578.     printf("none parity\n");
  579. #ifdef DEBUG
  580.   printf("fd = %d, modem control = %o\n", modem, mbits);
  581. #endif
  582.   printf("connect count: %d\n", connect_count);
  583.   ioctl(modem, TIOCOUTQ, &nb);
  584.   printf("outq: %d\n", nb);
  585.   printf("DialScript  = %s\n", VarDialScript);
  586.   printf("LoginScript = %s\n", VarLoginScript);
  587.   printf("PhoneNumber = %s\n", VarPhone);
  588.   return(1);
  589. }
  590.